#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System.Diagnostics;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Adoor.Expression.AST
{
	
	public abstract class ExpressionNode
	{
		public abstract void Accept(IExpressionVisitor visitor);
	}

	public class ExpressionEscape: ExpressionNode
	{
		public string Content;

		public ExpressionEscape() // for serialization purposes
		{
		}

		public ExpressionEscape(string content)
		{
			this.Content = content;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitEscape(this);
		}
	}

	public class ExpressionCorrelationFilteredNode: ExpressionNode
	{
		public IDictionary<string, ExpressionNode> Nodes;
		public ExpressionNode DefaultNode;
		public ExpressionName Qualifier;

		public ExpressionCorrelationFilteredNode() // for serialization purposes
		{

		}

        public ExpressionCorrelationFilteredNode(ExpressionName Qualifier, IDictionary<string, ExpressionNode> nodes, ExpressionNode defaultNode)
		{
            if (nodes.Count == 0)
                throw new System.ArgumentException(" 'nodes' parameter must have at least one element ");
			this.Qualifier = Qualifier;
			this.Nodes = nodes;
			this.DefaultNode = defaultNode;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitCorrelationFilteredNode(this);
		}
	}

	public class ExpressionName: ExpressionNode
	{
		public string Qualifier;
		public string Value;

		public ExpressionName() // for serialization purposes
		{
		}

		public ExpressionName(string qualifier, string value)
		{
            if (string.IsNullOrEmpty(value))
                throw new System.ArgumentException(" 'value' cannot be null or empty");
            if (qualifier == null)
                throw new System.ArgumentNullException(" 'qualifier' cannot be null");
			
            if (qualifier.StartsWith("[") && qualifier.EndsWith("]"))		// TODO: test should be in the parser
				qualifier = qualifier.Substring(1, qualifier.Length - 2);
			this.Qualifier = qualifier;
			if (value.StartsWith("[") && value.EndsWith("]")) // TODO: test should be in the parser
				value = value.Substring(1, value.Length - 2);
			this.Value = value;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitName(this);
		}
	}

	public class ExpressionParen: ExpressionNode
	{
		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Exp;

		public ExpressionParen() // for serialization purposes
		{
		}

		public ExpressionParen(ExpressionNode exp)
		{
			this.Exp = exp;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitParen(this);
		}
	}

	public class ExpressionPrimary: ExpressionNode
	{
		public ScannerToken Type;
		public string Value;

		public ExpressionPrimary() // for serialization purposes
		{
		}

		public ExpressionPrimary(ScannerToken type, string value)
		{
			this.Type = type;
			this.Value = value;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitPrimary(this);
		}
	}

	public class ExpressionIs: ExpressionNode
	{
		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Exp;

		public bool IsNot;

		public ScannerToken What;

		public ExpressionIs() // for serialization purposes
		{
		}

		public ExpressionIs(ExpressionNode exp, bool isNot, ScannerToken what)
		{
			this.Exp = exp;
			this.IsNot = isNot;
			this.What = what;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitIs(this);
		}
	}

	public class ExpressionIn: ExpressionNode
	{
		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Exp;

		public ExpressionNode[] Nodes;

		public ExpressionIn() // for serialization purposes
		{
		}

		public ExpressionIn(ExpressionNode exp, ExpressionNode[] nodes)
		{
			this.Exp = exp;
			this.Nodes = nodes;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitIn(this);
		}
	}

	public class ExpressionExistsSubquery: ExpressionNode
	{
		public object SubQuery;

		public ExpressionExistsSubquery() // for serialization purposes
		{
		}

		public ExpressionExistsSubquery(object subQuery)
		{
			this.SubQuery = subQuery;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitExistsSubQuery(this);
		}
	}

	public class ExpressionInSubquery: ExpressionNode
	{
		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Exp;

		public object SubQuery;

		public ExpressionInSubquery() // for serialization purposes
		{
		}

		public ExpressionInSubquery(ExpressionNode exp, object subQuery)
		{
			this.Exp = exp;
			this.SubQuery = subQuery;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitInSubQuery(this);
		}
	}

	public class ExpressionUnary: ExpressionNode
	{
		public ScannerToken Op;

		[XmlElement(typeof(ExpressionName))]
		[XmlElement(typeof(ExpressionEscape))]
		[XmlElement(typeof(ExpressionParen))]
		[XmlElement(typeof(ExpressionPrimary))]
		[XmlElement(typeof(ExpressionUnary))]
		[XmlElement(typeof(ExpressionBinary))]
		[XmlElement(typeof(ExpressionIs))]
		[XmlElement(typeof(ExpressionLike))]
		[XmlElement(typeof(ExpressionFunction))]
		public ExpressionNode Exp;

		public ExpressionUnary() // for serialization purposes
		{
		}

		public ExpressionUnary(ScannerToken op, ExpressionNode exp)
		{
			this.Op = op;
			this.Exp = exp;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitUnary(this);
		}
	}

	public class ExpressionBinary: ExpressionNode
	{
		public ScannerToken Op;

		[XmlElement("ExpessionName1", typeof(ExpressionName))]
		[XmlElement("ExpressionEscape1", typeof(ExpressionEscape))]
		[XmlElement("ExpressionParen1", typeof(ExpressionParen))]
		[XmlElement("ExpressionPrimary1", typeof(ExpressionPrimary))]
		[XmlElement("ExpressionUnary1", typeof(ExpressionUnary))]
		[XmlElement("ExpressionBinary1", typeof(ExpressionBinary))]
		[XmlElement("ExpressionIs1", typeof(ExpressionIs))]
		[XmlElement("ExpressionLike1", typeof(ExpressionLike))]
		[XmlElement("ExpressionFunction1", typeof(ExpressionFunction))]
		public ExpressionNode Exp1;

		[XmlElement("ExpressionName2", typeof(ExpressionName))]
		[XmlElement("ExpressionEscape2", typeof(ExpressionEscape))]
		[XmlElement("ExpressionParen2", typeof(ExpressionParen))]
		[XmlElement("ExpressionPrimary2", typeof(ExpressionPrimary))]
		[XmlElement("ExpressionUnary2", typeof(ExpressionUnary))]
		[XmlElement("ExpressionBinary2", typeof(ExpressionBinary))]
		[XmlElement("ExpressionIs2", typeof(ExpressionIs))]
		[XmlElement("ExpressionLike2", typeof(ExpressionLike))]
		[XmlElement("ExpressionFunction2", typeof(ExpressionFunction))]
		public ExpressionNode Exp2;

		public ExpressionBinary() // for serialization purposes
		{
		}

		public ExpressionBinary(ScannerToken op, ExpressionNode exp1, ExpressionNode exp2)
		{        	
			this.Op = op;
			this.Exp1 = exp1;
			this.Exp2 = exp2;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitBinary(this);
		}
	}

	public class ExpressionLike: ExpressionNode
	{
		[XmlElement("ExpressionName1", typeof(ExpressionName))]
		[XmlElement("ExpressionEscape1", typeof(ExpressionEscape))]
		[XmlElement("ExpressionParen1", typeof(ExpressionParen))]
		[XmlElement("ExpressionPrimary1", typeof(ExpressionPrimary))]
		[XmlElement("ExpressionUnary1", typeof(ExpressionUnary))]
		[XmlElement("ExpressionBinary1", typeof(ExpressionBinary))]
		[XmlElement("ExpressionIs1", typeof(ExpressionIs))]
		[XmlElement("ExpressionLike1", typeof(ExpressionLike))]
		[XmlElement("ExpressionFunction1", typeof(ExpressionFunction))]
		public ExpressionNode Exp1;

		public bool IsNotLike;

		[XmlElement("ExpressionName2", typeof(ExpressionName))]
		[XmlElement("ExpressionEscape2", typeof(ExpressionEscape))]
		[XmlElement("ExpressionParen2", typeof(ExpressionParen))]
		[XmlElement("ExpressionPrimary2", typeof(ExpressionPrimary))]
		[XmlElement("ExpressionUnary2", typeof(ExpressionUnary))]
		[XmlElement("ExpressionBinary2", typeof(ExpressionBinary))]
		[XmlElement("ExpressionIs2", typeof(ExpressionIs))]
		[XmlElement("ExpressionLike2", typeof(ExpressionLike))]
		[XmlElement("ExpressionFunction2", typeof(ExpressionFunction))]
		public ExpressionNode Exp2;

		public ExpressionLike() // for serialization purposes
		{
		}

		public ExpressionLike(ExpressionNode exp1, bool isNotLike, ExpressionNode exp2)
		{        	
			this.Exp1 = exp1;
			this.IsNotLike = isNotLike;
			this.Exp2 = exp2;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitLike(this);
		}
	}

	public class ExpressionFunction: ExpressionNode
	{
		public string Name;

		[XmlArrayItem(typeof(ExpressionName))]
		[XmlArrayItem(typeof(ExpressionEscape))]
		[XmlArrayItem(typeof(ExpressionParen))]
		[XmlArrayItem(typeof(ExpressionPrimary))]
		[XmlArrayItem(typeof(ExpressionUnary))]
		[XmlArrayItem(typeof(ExpressionBinary))]
		[XmlArrayItem(typeof(ExpressionIs))]
		[XmlArrayItem(typeof(ExpressionLike))]
		[XmlArrayItem(typeof(ExpressionFunction))]
		public ExpressionNode[] Parameters;

		public ExpressionFunction() // for serialization purposes
		{
		}

		public ExpressionFunction(string name, params ExpressionNode[] parameters)
		{
			this.Name = name;
			this.Parameters = parameters;
		}

		public override void Accept(IExpressionVisitor visitor)
		{
			visitor.VisitFunction(this);
		}
	}
}